Repository navigation
fix: Report watched file changes promptly with watchdog 7, and react to a touch - #577
Merged
Merged
Conversation
…to a touch watchdog 7 on Windows holds notifications for the observer timeout, one second by default, and delivers none while another file in the directory changes more often. The watcher now uses a 100 ms timeout. watchdog 7 reports a touch as an attrib event, which now counts as a change. After scheduling a watch, the watcher yields so that the reader thread of watchdog 6 on Windows asks for notifications before the setup goes on.
keelerm84
approved these changes
Nov 12, 2026
kinyoklion
added a commit
that referenced
this pull request
Nov 12, 2026
<!-- TERMAG_PR_BODY_BEGIN --> BEGIN_COMMIT_OVERRIDE feat: Add experimental support for flag overrides, read from local JSON or YAML files or supplied by a custom override source feat: Mark evaluations that a flag override affected with `overrideAffected` in the evaluation reason, and count them under separate summary counters fix: Stop the components that already started when the client fails to start END_COMMIT_OVERRIDE Every change in this PR was already reviewed and merged through its own PR against `feat/overrides`: #525, #526, #527, #528, #529, #530, #572, #574, #576, #577. This PR merges the branch into `main`. Flag overrides let an operator force flags and segments to known definitions on a running client, whether or not the client can reach LaunchDarkly, and remove the override when the incident is over. They are an option of the FDv2 data system, on both `LDClient` and `AsyncLDClient`, with a file-based source in `ldclient.integrations.overrides.FileOverrideSourceBuilder`, and are experimental. The one change outside the feature: #527 stops the components that had already started when the data system fails to start, so a failed client construction no longer leaves threads behind. `main` was merged into `feat/overrides` in 46e5f0e, so the branch has every `main` commit. That merge resolved two conflicts and made one follow-up change: - The capability lists of both contract test services keep both sides: `flag-overrides` from this branch, and the retry conformance, service endpoints, wrapper, proxy and TLS capabilities from `main`. - One async override test used `AsyncHook`, which #548 removed from `main`. It now uses `Hook`, which the async client accepts. Before the push: - the unit test suite passed (2,357 tests, without the Redis, DynamoDB and Consul store tests, which need servers); - `mypy`, `isort` and `pycodestyle` were clean; - the contract test harness's `flag overrides` suite passed against both the sync and the async test service (88 tests each). <!-- TERMAG_PR_BODY_END --> <!-- termag: box=i-0575d1c54853058d7 project=python-server-sdk --> <sub>Opened from termag</sub> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Adds **experimental flag overrides** so operators can force known flag/segment definitions at runtime (via local JSON/YAML files through `FileOverrideSourceBuilder`, or a custom `OverrideSource`), integrated into the FDv2 data system for sync and async clients through `datasystem_config.override_source` / `ConfigBuilder.overrides()`. > > The data system now maintains an **override layer** merged over the normal store, serves override-only flags when LaunchDarkly data is not ready, and fans out **dependency-aware flag-change notifications** when LD data affects overridden prerequisites/segments. Evaluations propagate an **`overrideAffected`** reason marker; analytics treat those evaluations differently (summary counters only, `all_flags_state` disables per-flag tracking for them). > > Contract test services advertise **`flag-overrides`** and build override sources from harness config; docs add `ldclient.integrations.overrides`. > > Also **fixes client startup**: if the data system fails to start, already-started components are stopped so failed construction does not leak threads. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 46e5f0e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requirements
async_*siblings (or N/A). N/A: the file watcher serves both clients.Related issues
This resolves the SDK findings of the Windows stability assessment for the overrides work: plans/python-overrides-windows-test-stability.md in sdk-scratchpad.
Describe the solution you've provided
All three changes are in
Watcher, inldclient/impl/integrations/files/filedata.py, which the file-based override source uses in watching mode.timeout=0.1. On Linux, the timeout only sets how often the idle inotify loop wakes.watchdog>=3.0.0, so this affects any Windows deployment that selectsChangeDetection.WATCHING.os.utime, as anattribevent. Earlier versions reported it asmodified.attrib, so touching a file to force a reload stopped working in watching mode, while it still works in polling mode.attribnow counts as a change. A plain read does not produce it, so the reloads stay quiet. The reloader's content digest still skips applying an unchanged file.Tests in
test_filedata.py:Describe alternatives you've considered
watchdog<7in thetest-filesourceextra. Applications bring their own watchdog, so a pin would only hide the behavior from CI.attrib. That would leave watching and polling behaving differently for the same file.Additional context
Testing:
mypy,isortandpycodestyleare clean.This PR merges cleanly with #574 and #576.
Not in this PR, from Finding 6 of the assessment. None of these come from the overrides work:
test_async_migrator.pythat is too tight for Windows clocks;main;feat/overridesred in 4 of 5 runs and needs its own investigation before the merge intomain.The assessment also recommends reporting the watchdog 7 behavior upstream; that is not done yet.
Opened from termag
Note
Overview
Updates the file
Watcherin watching mode so override/data reloads behave reliably with watchdog 6–7, especially on Windows.The observer now uses a 100 ms delivery timeout instead of watchdog’s 1 s default, so changes are reported quickly and are not indefinitely delayed when another file in the same directory keeps notifying.
attribis treated as a content-relevant event so a mtime-only touch triggers a reload again under watchdog 7. After each directory watch is scheduled, a thread yield (time.sleep(0)) avoids missing an immediate post-start change on watchdog 6 for Windows.New watcher tests cover sub-second latency, detection alongside a busy log file, and mtime-only updates.
Reviewed by Cursor Bugbot for commit 546a7f5. Bugbot is set up for automated code reviews on this repo. Configure here.